﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TakaGUI.IO;
using System.Collections;

namespace EvoSim.Simulation.Genes
{
	public interface INeuralNetChromosome : IGeneInfoHolder
	{
		int EyeNeuronsCount { get; }

		DoubleGene CrossoverRate { get; }
		DoubleGene MutationChance { get; }

		IList<IDObject> Inputs { get; }
		IList<IDObject> Hidden { get; }
		IList<IDObject> Outputs { get; }

		void Initialize(Genome genome);
		INeuralNet GetNeuralNet();
		void Randomize(int eyeNeurons, int inputs, int outputs, int hidden);
		INeuralNetChromosome CrossoverWith(INeuralNetChromosome c2, CrossoverFunction crossoverFunction);
		void Mutate();
	}

	public abstract class NeuralNetChromosome<TSettings> : INeuralNetChromosome
		where TSettings : NeuralChromosomeSettings
	{
		protected Genome Genome;

		public abstract int EyeNeuronsCount { get; }

		public DoubleGene CrossoverRate { get { return Genome.CrossoverRate; } }
		public DoubleGene MutationChance { get { return Genome.MutationChance; } }

		public abstract IList<IDObject> Inputs { get; }
		public abstract IList<IDObject> Hidden { get; }
		public abstract IList<IDObject> Outputs { get; }

		public TSettings Settings { get; set; }

		public NeuralNetChromosome()
		{
		}
		public NeuralNetChromosome(TSettings settings)
		{
			SetSettings(settings);
		}

		public void Initialize(Genome genome)
		{
			if (genome == null)
				throw new NullReferenceException();

			Genome = genome;
		}

		public virtual void SetSettings(TSettings settings)
		{
			Settings = settings;
		}

		public abstract INeuralNet GetNeuralNet();

		public abstract void Randomize(int eyeNeurons, int inputs, int outputs, int hidden);

		public abstract INeuralNetChromosome CrossoverWith(INeuralNetChromosome c2, CrossoverFunction crossoverFunction);
		public abstract void Mutate();

		protected static void MutateGeneList<T>(List<T> geneList, double mutationChance) where T : Gene
		{
			foreach (var gene in geneList)
				gene.TryToMutate(mutationChance);
		}

		public abstract GeneInfo GetGeneInfo();
	}
}
